package wpmp.security.client.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;

import wcommons.lang.UrlUtils;
import wpmp.security.client.SecurityConfig;
import wpmp.security.client.internal.PmpButtonConfigUtils;
import wpmp.security.client.internal.PmpResourceUtils;
import wpmp.security.client.log.AppContextLogFactory;
import wpmp.security.client.log.LogUtil;
import wpmp.security.client.utils.UserUtils;
import wpmp.utils.Statics;

/**
 * 对请求进行拦截，验证权限
 * 
 * <pre>
 *  以下需要配置在web.xml中：
 *  <filter>
 * 		<filter-name>SecurityFilter</filter-name>
 * 		<filter-class>wpmp.security.client.filter.SecurityFilter</filter-class>
 * 		<init-param>
 *			<param-name>logger.dir</param-name>
 *			<!-- 日志的输出目录，可选项，优先级：(logger.dir) > (Root Logger上设置的FileAppender) > (当前用户目录/logs/) -->
 *			<param-value></param-value>
 *		</init-param>
 * 	</filter>
 * 	<filter-mapping>
 * 		<filter-name>SecurityFilter</filter-name>
 * 		<url-pattern>*.action</url-pattern>
 * 	</filter-mapping>
 * 	<filter-mapping>
 * 		<filter-name>SecurityFilter</filter-name>
 * 		<url-pattern>*.do</url-pattern>
 * 	</filter-mapping>
 *  以下可以配置在spring配置文件中，或手动初始化：
 *  <bean class="wpmp.security.client.SecurityConfig" init-method="initByProperties" lazy-init="false" />
 * </pre>
 * @author Wayne.Wang<5waynewang@gmail.com>
 * @since 2:57:46 PM Dec 24, 2012
 */
public class SecurityFilter implements Filter {

	protected final Log log = LogUtil.getLog();

	protected boolean isAjaxRequest(HttpServletRequest req) {
		return StringUtils.equals(req.getHeader("X-Requested-With"), "XMLHttpRequest");
	}

	/**
	 * 判断用户是否能访问资源及操作
	 * @param req
	 * @param resp
	 * @return
	 * @throws IOException
	 * @throws ServletException
	 */
	@SuppressWarnings("unchecked")
	protected boolean check(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		final int statusCode = PmpResourceUtils.checkPermission(req, resp);
		if (statusCode == StatusCode.NO_PERMISSION) {
			throw new DeniedAccessException("对不起，您没有权限访问 [" + req.getRequestURL().toString() + "]");
		}
		// 重定向至登录页面
		if (statusCode == StatusCode.NOT_LOGIN) {
			if (this.isAjaxRequest(req)) {
				resp.addHeader(Statics.REDIRECT_LOCATION, SecurityConfig.getLoginUrl());
				resp.sendError(StatusCode.AJAX_SEND_REDIRECT_ERROR, AjaxSendRedirectException.class.getSimpleName());
				return false;
			}
			resp.sendRedirect(SecurityConfig.getLoginUrl());
			return false;
		}

		final StringBuilder sb = new StringBuilder();
		sb.append("User[").append(UserUtils.getLoginName(req)).append("]");
		sb.append(" do ").append(req.getMethod()).append(" request to URL[").append(req.getRequestURL()).append("], ");
		sb.append(UrlUtils.getStringParams(req.getParameterMap()));

		log.info(sb.toString());

		return true;
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,
			ServletException {
		if (check((HttpServletRequest) req, (HttpServletResponse) resp)) {
			chain.doFilter(req, resp);
		}
	}

	@Override
	public void init(FilterConfig config) throws ServletException {
		// 初始化日志配置
		AppContextLogFactory.holder().setLoggerDir(config.getInitParameter("logger.dir")).init();
		// 初始化按钮设置
		PmpButtonConfigUtils.init();
	}

	@Override
	public void destroy() {
	}

}
